!> 文件系统模块
!> 提供文件和目录操作的基本功能，包括:
!> - 文件/目录存在性检查
!> - 路径拼接操作符 (.join.)
!> - 路径格式转换 (Unix/Windows)
!> - 文本文件读取
!> - 目录创建
!>
!> 主要功能:
!> - exists: 检查文件或目录是否存在
!> - .join.: 连接路径和文件名
!> - unix_path: 将路径转换为 Unix 格式
!> - read_text_file: 读取文本文件内容
!> - mkdir: 创建目录
!>
!> 在非 MKL 环境下还提供:
!> - openblas_set_num_threads: 设置 OpenBLAS 线程数
module filesystem_module

  use, intrinsic :: iso_c_binding, only: c_int
  use stdlib_io, only: open
  implicit none

  interface operator(.join.)
    module procedure :: join
  end interface

#ifndef MKL
  interface
    subroutine openblas_set_num_threads(num_threads) bind(C, name='openblas_set_num_threads')
      import :: c_int
      integer(c_int), value :: num_threads
    end subroutine openblas_set_num_threads
  end interface
#endif

contains

  !> 为 Windows 设置控制台编码为 UTF-8, 高效、轻量级系统 API 调用, 支持 Win7 以上版本
  subroutine set_console_encoding()
    integer(c_int) :: result

#ifdef _WIN32
    interface
      function SetConsoleOutputCP(wCodePageID) bind(c, name='SetConsoleOutputCP')
        import c_int
        integer(c_int) :: SetConsoleOutputCP
        integer(c_int), value :: wCodePageID
      end function
    end interface

    result = SetConsoleOutputCP(65001)  ! 设置控制台输出编码为 UTF-8
#endif

  end subroutine set_console_encoding

  !> 查询文件路径是否存在
  logical function exists(filename)
    character(len=*), intent(in) :: filename  !< 路径名

    inquire (file=filename, exist=exists)

#ifdef __INTEL_COMPILER
    if (.not. exists) inquire (directory=filename, exist=exists)
#endif

  end function exists

  !> 连接路径
  pure function join(path, filename)
    character(len=*), intent(in) :: path, filename
    character(len_trim(path) + len_trim(filename) + 1) :: join

    join = trim(path)//"/"//trim(filename)

  end function join

  !> 转化为 unix 路径, unix 路径全平台可用
  pure function unix_path(path)
    character(len=*), intent(in) :: path
    character(len=len_trim(path)) :: unix_path
    integer :: i

    do i = 1, len_trim(path)
      if (path(i:i) == "\") then
        unix_path(i:i) = "/"
      else
        unix_path(i:i) = path(i:i)
      end if
    end do

  end function unix_path

  !> 转化为 Windows 路径
  pure function windows_path(path)
    character(len=*), intent(in) :: path
    character(len=len_trim(path)) :: windows_path
    integer :: i

    do i = 1, len_trim(path)
      if (path(i:i) == "/") then
        windows_path(i:i) = "\"
      else
        windows_path(i:i) = path(i:i)
      end if
    end do

  end function windows_path

  !> read text file into a string
  function read_text_file(filename) result(string)
    character(len=*), intent(in) :: filename  !< 文件名
    character(len=:), allocatable :: string
    integer :: fh, length

    fh = open (filename, "rb")
    inquire (fh, size=length)
    allocate (character(len=length) :: string)
    if (length == 0) return
    read (fh) string
    close (fh)

  end function read_text_file

  subroutine mkdir(path)
    character(len=*), intent(in) :: path

    if (is_windows()) then
      call execute_command_line("md "//windows_path(path))
    else
      call execute_command_line("mkdir -p "//path)
    end if

  end subroutine mkdir

  logical function is_windows()
    character(16) :: os_name
    logical, save :: is_windows_ = .false.
    logical, save :: is_first_run = .true.

    if (is_first_run) then
      call get_environment_variable("OS", os_name)
      is_windows_ = trim(os_name) == "Windows_NT"
      is_first_run = .false.
      is_windows = is_windows_
    else
      is_windows = is_windows_
    end if
  end function is_windows

end module filesystem_module
